/**
 * 	Fichier contenant les différentes règles de traitement des mots du language reconnu.
 *
 *	@file 		draw.y
 *	@author 	Jacquemin Thibault Marleix Mathieu
 *	@version 	0.5
 *
 */

%{
#include <stdio.h>
#include <string.h>
#include "arbre.h"

int yylex(void);
int child = 0;
void yyerror(char *);
extern FILE *yyin;
FILE *yyout;
char libelle[10];
%}

%union{
	float f;
	char* str;
	struct node * t;
}

%token <str> WORD DRAW COMMENTARY FOR IF ELSE FUNCTION
%token <f> FLOAT

%type <t> program function expr argument number var assign comparison commentary loop condition draw parameter definition

%left '+' '-'
%left '*' '/'

%%

/*
 *	Règle lançant la traduction de l'arbre généré. 
 */
result: 	program 				{ interpretNode($1,yyout); }
	 ;

/*
 *	Règle définissant les différents cas de mots actuellement parsable dans le fichier d'entrée. 
 */	 
program:							{ $$ = createNode(NODEEMPTY,0,0); }
			| program draw	';'		{ assemble($1, $2); }
			| program function ';' 	{ assemble($1, $2); }
			| program assign ';'	{ assemble($1, $2); }
			| program commentary	{ assemble($1, $2); }
			| program loop			{ assemble($1, $2); }
			| program condition		{ assemble($1, $2); }
			| program definition	{ assemble($1, $2); }
			| program parameter		{ assemble($1, $2); }
	;

/*
 *	Règle définissant les différents arguments possiblement passés lors de l'appel d'une fonction. 
 */
argument:  	expr 					{$$ = createNode(NODEEMPTY,0,0); assemble($$, $1);}
		 	| argument ',' expr 	{assemble($1,$3); $$ = $1;}
	 ;
/*
 *	Règle définissant les différents paramètres employés lors de la définition d'une fonction. 
 */
parameter:  	var 					{$$ = createNode(NODEEMPTY,0,0); assemble($$, $1);}
		 	| parameter ',' var 	{assemble($1,$3); $$ = $1;}
	 ;

/*---------- Question 2.1 ----------------------*/

/*
 *	Règle traitant la fonction draw. 
 */
draw: 	DRAW '(' expr ',' expr ',' expr ',' expr ')' {
		sprintf(libelle,"%d",OPDRAW); $$ = createNode(NODEOP, libelle, 4, $3, $5, $7, $9);
	}
	;

/*---------- Question 2.4 ----------------------*/

/*
 *	Règle traitant les cas d'opérateurs mathématique.
 */
expr:		var
			| number
			| expr '+' expr 	{ sprintf(libelle,"%d",OPPLUS); $$ = createNode(NODEOP, libelle,2, $1,$3);}
			| expr '-' expr 	{ sprintf(libelle,"%d",OPMINUS); $$ = createNode(NODEOP, libelle,2, $1,$3); }
			| '-' expr 			{ tree t = createNode(NODEFLOAT, "NULL",0); sprintf(libelle,"%d",OPMINUS); $$ = createNode(NODEOP, libelle,2, t, $2);}
			| expr '*' expr 	{ sprintf(libelle,"%d",OPMUL);  $$ = createNode(NODEOP, libelle,2, $1,$3); }
			| expr '/' expr 	{ sprintf(libelle,"%d",OPDIV); $$ = createNode(NODEOP, libelle,2, $1,$3); }
			| '(' expr ')' 		{ $$ = $2; }
	;

/*
 *	Règle traitant les cas d'opérateurs logique.
 */
comparison: 	expr '=''=' expr 	{sprintf(libelle,"%d",OPEQ); $$ = createNode(NODEOP, libelle,2, $1,$4);}
		 	| expr '>''=' expr 	{sprintf(libelle,"%d",OPGEQ); $$ = createNode(NODEOP, libelle,2, $1,$4);}
		 	| expr '<''=' expr 	{sprintf(libelle,"%d",OPLEQ); $$ = createNode(NODEOP, libelle,2, $1,$4);}
		 	| expr '!''=' expr 	{sprintf(libelle,"%d",OPNEQ); $$ = createNode(NODEOP, libelle,2, $1,$4);}
		 	| expr '>' expr 	{sprintf(libelle,"%d",OPGT); $$ = createNode(NODEOP, libelle,2, $1,$3);}
		 	| expr '<' expr 	{sprintf(libelle,"%d",OPLT); $$ = createNode(NODEOP, libelle,2, $1,$3);}
	;

/*---------- Question 2.6 ----------------------*/

/*
 *	Règle traitant la boucle for.
 */
loop:		FOR '(' assign ';' comparison ';' assign ')' '{' program '}' 
	{
			sprintf(libelle,"%d",OPLOOP); $$ = createNode(NODEOP, libelle, 4, $3, $5, $7, $10);
	}

/*---------- Question 2.7 ----------------------*/

/*
 *	Règles traitant les tests if/else.
 */
condition:		IF '(' comparison ')' '{' program '}' 
	{
			sprintf(libelle,"%d",OPIF); $$ = createNode(NODEOP, libelle, 2, $3, $6);
	}
	
			|	IF '(' comparison ')' '{' program '}' ELSE '{' program '}'
	{
			sprintf(libelle,"%d",OPELSE); $$ = createNode(NODEOP, libelle, 3, $3, $6, $10);
	}

/*------------- Question 2.3 -------------------*/	

/*
 *	Règle traitant une assignation de variable.
 */
assign: var '=' expr {sprintf(libelle,"%d",OPASSIGN); $$ = createNode(NODEOP, libelle,2, $1,$3);}

/*
 *	Règle traitant un appel de variable ou un identifiant.
 */
var:  WORD	
	{
		$$ = createNode(NODESTRING,$1,0);
	}

/*
 *	Règle traitant un nombre flottant.
 */	
number: FLOAT 
	{ 
		$$ = createNode(NODEFLOAT,"NULL", $1);
	}

/*------------- Question 2.5 -------------------*/	

/*
 *	Règle traitant les commentaires.
 */	
commentary:	COMMENTARY {$$ = createNode(NODECOM,$1,0); }
	;

/*------------- Question 2.8 -------------------*/

/*
 *	Règles traitant une définition de fonction.
 */
definition: FUNCTION var '(' ')' '{' program '}' 
	{
			if(DEBUG) fprintf(stdout,"plop\n");
			sprintf(libelle,"%d",OPDEF);
			tree t = createNode(NODEEMPTY,0,0);
			$$ = createNode(NODEOP,libelle, 3, $2, t, $6);
	}
		|	FUNCTION var '(' parameter ')' '{' program '}'
	{
			sprintf(libelle,"%d",OPDEF);
			$$ = createNode(NODEOP, libelle,3,$2,$4,$7);
	}

/*
 *	Règles traitant un appel de fonction.
 */
function: 	var '(' ')' 
	{
			sprintf(libelle,"%d",OPFUNC);
			tree t = createNode(NODEEMPTY,0,0);
			$$ = createNode(NODEOP,libelle, 3, $1,t);
	}
		|	var '(' argument ')'
	{		
			sprintf(libelle,"%d",OPFUNC);
			$$ = createNode(NODEOP, libelle,2,$1,$3);
	}


%%

void yyerror(char *s) {
	extern char* yytext;
	fprintf(stderr, "%s: [%s]\n", s, yytext);
}

void usage(char *progname){
	fprintf(stdout,"Usage: %s [Input file] [OPTIONS]\n '%s --help' pour plus d'options\n",progname,progname);
}


/**
 *	Fonction principale du programme de traduction C-like vers Poscript
 *
 * 	@fn 		int 		main(int argc, char *argv[])
 *	@param[in]	argc		Nombre d'arguments.
 *	@param[in]	argv		Pointeur sur les arguments.
 *	@return		int			La valeur de sortie du programme.
 */
int main(int argc, char *argv[]) {
	if (argc<2) usage(argv[0]);
	else if(argc == 2){
		if(!strcmp(argv[1],"--help")){
			fprintf(stdout,"Options de l'application :\n");
			fprintf(stdout," --debug 	Active l'affichage de déboggage à 1, à 0 par défault\n");
			fprintf(stdout," --output	spécifie le nom fichier de sortie sans l'extension\n");
		}
		else{
			DEBUG = 0;
			fprintf(stdout,"Input filename: %s\n", argv[1]);
			yyin = fopen(argv[1], "r");
			char * posFile = strtok(argv[1], ".");
			strncat(posFile, ".ps",sizeof(argv[1]));
			fprintf(stdout,"Output filename: %s\n", posFile);
			yyout = fopen(posFile, "w+");
			fprintf(yyout, "%%!\n");
			fprintf(stdout,"Starting transcription\n");
			yyparse();
			fprintf(stdout,"Transcription finished\n");
			fclose(yyin);
			fclose(yyout);
		}
	}
	else if(argc == 4){
		char * outputFile = malloc(25*sizeof(char));
		if(!strcmp(argv[2],"--debug")){
			DEBUG = atoi(argv[3]);
			strcpy(outputFile,argv[1]);
			strncat(strtok(outputFile, "."), ".ps",sizeof(argv[3]));
		}
		else if(!strcmp(argv[2],"--output")){
			strcpy(outputFile,argv[3]);
			outputFile = strncat(strtok(outputFile, "."),".ps",sizeof(argv[3]));
		}
		else {usage(argv[0]); return 0;}
		
		fprintf(stdout,"Input filename: %s\n", argv[1]);
		yyin = fopen(argv[1], "r");
		fprintf(stdout,"Output filename: %s\n", outputFile);
		yyout = fopen(outputFile, "w+");
		fprintf(yyout, "%%!\n");
		fprintf(stdout,"Starting transcription\n");
		yyparse();
		fprintf(stdout,"Transcription finished\n");
		fclose(yyin);
		fclose(yyout);
	}
	
	else if(argc == 6){
		char * outputFile = malloc(25*sizeof(char));
		int i;
		for(i=2;i<argc;i++){
			if(!strcmp(argv[i],"--debug")){
				DEBUG = atoi(argv[++i]);
			}
			else if(!strcmp(argv[i],"--output")){
				strcpy(outputFile,argv[++i]);
				outputFile = strncat(strtok(outputFile, "."),".ps",sizeof(argv[++i]));
			}
			else {usage(argv[0]); return 0;}
		}
			
		if(DEBUG) fprintf(stdout,"Debug: %d\n",DEBUG);
		fprintf(stdout,"Input filename: %s\n", argv[1]);
		yyin = fopen(argv[1], "r");
		fprintf(stdout,"Output filename: %s\n", outputFile);
		yyout = fopen(outputFile, "w+");		
		fprintf(yyout, "%%!\n");
		fprintf(stdout,"Starting transcription\n");
		yyparse();
		fprintf(stdout,"Transcription finished\n");
		fclose(yyin);
		fclose(yyout);
	}
	else usage(argv[0]);
	return EXIT_SUCCESS;
}
